package com.hexinfo.dmpro.component.common.service.impl;

import cn.hutool.core.util.StrUtil;
import com.hexinfo.dmpro.component.common.entity.TableFieldsEntity;
import com.hexinfo.dmpro.component.common.exception.BizException;
import com.hexinfo.dmpro.component.common.service.IDatabaseQueryService;
import com.hexinfo.dmpro.component.common.util.DataSourceUtil;
import liquibase.pro.packaged.S;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.sql.*;
import java.util.*;

@Slf4j
@Component
public class ImpalaQueryService implements IDatabaseQueryService {

    // 表明细数据查询批次梳理
    private final static int FETCH_SIZE = 15000;

    // 表明细数据查询超时时长（秒）
    private final static int QUERY_TIMEOUT = 7200;

    private final static String IMPALA_NUMBER_TYPE[] = {"tinyint", "smallint", "int", "bigint", "float", "double"};

    /*
     * @Method: isTableExist <br>
     * @Param: [dbName, tableName] <br>
     * @Return: void <br>
     * @Description：判断指定表是否存在<br>
     * @Author： wz.li<br>
     * @Date： 2023/9/25 17:26 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public void isTableExist(Connection connection, String dbName, String tableName) {
        Statement statement = null;
        ResultSet resultSet = null;
        try {
            statement = connection.createStatement();
            String template = "SHOW TABLES IN {} LIKE '{}'";
            resultSet = statement.executeQuery(StrUtil.format(template, dbName, tableName));
            if (!resultSet.next()) {
                throw new BizException(StrUtil.format("表[{}.{}]不存在！", dbName, tableName));
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        } finally {
            DataSourceUtil.close(statement, resultSet);
        }
    }

    /*
     * @Method: queryTotalCount <br>
     * @Param: [conn, dbTableName, queryCriteria, queryFlag] <br>
     * @Return: long <br>
     * @Description：指定表数据总量查询<br>
     * @Author： wz.li<br>
     * @Date： 2023/9/25 16:08 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public long queryTotalCount(Connection connection, String dbTableName, String queryCriteria, String queryFlag) {
        Statement statement = null;
        ResultSet resultSet = null;
        try {
            statement = connection.createStatement();
            String template = "select count(1) from {} {}";
            resultSet = statement.executeQuery(StrUtil.format(template, dbTableName, queryCriteria));
            resultSet.next();
            return resultSet.getLong(1);
        } catch (Exception e) {
            throw new RuntimeException(StrUtil.format("{} 表查询总条数异常: {}", queryFlag, e.getMessage()), e);
        } finally {
            DataSourceUtil.close(statement, resultSet);
        }
    }

    /*
     * @Method: queryTableMetadata <br>
     * @Param: [conn, dbTableName, queryFlag] <br>
     * @Return: java.util.List<com.hexinfo.dmpro.component.common.entity.TableFieldsEntity> <br>
     * @Description：指定表元数据查询<br>
     * @Author： wz.li<br>
     * @Date： 2023/9/25 16:20 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public List<TableFieldsEntity> queryTableMetadata(Connection conn, String dbTableName, String queryFlag) {
        Statement statement = null;
        ResultSet resultSet = null;
        List<TableFieldsEntity> tableFieldsEntities = new ArrayList<>();
        try {
            statement = conn.createStatement();
            String template = "DESCRIBE {} ";
            resultSet = statement.executeQuery(StrUtil.format(template, dbTableName));
            while (resultSet.next()) {
                ResultSetMetaData metaData = resultSet.getMetaData();
                Map<String, String> tableFieldsMap = new HashMap<>();
                for (int i = 1; i <= metaData.getColumnCount(); i++) {
                    tableFieldsMap.put(metaData.getColumnName(i), resultSet.getString(i));
                }
                tableFieldsEntities.add(toTableFields(tableFieldsMap));
            }
            return tableFieldsEntities;
        } catch (Exception e) {
            throw new RuntimeException(StrUtil.format("{} 表元数据获取异常: {}", queryFlag, e.getMessage()), e);
        } finally {
            DataSourceUtil.close(statement, resultSet);
        }
    }

    /*
     * @Method: toTableFields <br>
     * @Param: [tableFieldsMap] <br>
     * @Return: com.hexinfo.dmpro.component.common.entity.TableFieldsEntity <br>
     * @Description：元数据Map集合转List对象<br>
     * @Author： wz.li<br>
     * @Date： 2023/9/25 16:25 <br>
     * @Version： V2.0.2<br>
     */
    private TableFieldsEntity toTableFields(Map<String, String> tableFieldsMap) {
        if (tableFieldsMap == null) {
            return null;
        }
        TableFieldsEntity tableFieldsEntity = new TableFieldsEntity();
        if (tableFieldsMap.containsKey("name")) {
            tableFieldsEntity.setName(tableFieldsMap.get("name"));
        }
        if (tableFieldsMap.containsKey("type")) {
            tableFieldsEntity.setType(tableFieldsMap.get("type"));
        }
        if (tableFieldsMap.containsKey("comment")) {
            tableFieldsEntity.setComment(tableFieldsMap.get("comment"));
        }
        return tableFieldsEntity;
    }

    /*
     * @Method: queryTableDetailedData <br>
     * @Param: [conn, dbTableName, queryCriteria, queryFlag] <br>
     * @Return: java.sql.ResultSet <br>
     * @Description：指定表明细数据查询<br>
     * @Author： wz.li<br>
     * @Date： 2023/9/25 16:09 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public ResultSet queryTableDetailedData(Connection conn, String dbTableName, String queryCriteria, String queryFlag) {
        Statement statement = null;
        try {
            statement = conn.createStatement();
            statement.setFetchSize(FETCH_SIZE);
            statement.setQueryTimeout(QUERY_TIMEOUT);
            String template = "select * from {} {}";
            String baseSql = StrUtil.format(template, dbTableName, queryCriteria);
            return statement.executeQuery(baseSql);
        } catch (Exception e) {
            throw new RuntimeException(StrUtil.format("{} 表明细数据查询异常: {}", queryFlag, e.getMessage()), e);
        }
    }

    /*
     * @Method: queryTableStatisticsData <br>
     * @Param: [conn, dbTableName, queryCriteria, queryFlag] <br>
     * @Return: java.util.Map <br>
     * @Description：查询指定库表的统计数据<br>
     * @Author： wz.li<br>
     * @Date： 2023/9/26 17:30 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public Map<String, String> queryTableStatisticsData(Connection conn, String dbTableName, String queryCriteria, String queryFlag) {
        Statement statement = null;
        ResultSet resultSet = null;
        String template = "select {} from {} {}";
        Map<String, String> tableStatisticsDataMap = new HashMap<>();
        try {
            List<TableFieldsEntity> tableFieldsEntities = queryTableMetadata(conn, dbTableName, queryFlag);
            statement = conn.createStatement();
            resultSet = statement.executeQuery(StrUtil.format(template, buildTableStatisticsDatadQueryField(tableFieldsEntities), dbTableName, queryCriteria));
            while (resultSet.next()) {
                ResultSetMetaData metaData = resultSet.getMetaData();
                for (int i = 1; i <= metaData.getColumnCount(); i++) {
                    tableStatisticsDataMap.put(metaData.getColumnName(i), resultSet.getString(i));
                }
            }
            return tableStatisticsDataMap;
        } catch (Exception e) {
            throw new RuntimeException(StrUtil.format("{} 表哈希数据查询异常: {}", queryFlag, e.getMessage()), e);
        } finally {
            DataSourceUtil.close(statement, resultSet);
        }
    }

    /*
     * @Method: buildTableStatisticsDatadQueryField2 <br>
     * @Param: [tableFieldsEntities] <br>
     * @Return: java.lang.String <br>
     * @Description：获取每个字段的哈希值和、字符串长度和、数值类型和、其他类型转成字符串长度和<br>
     * @Author： wz.li<br>
     * @Date： 2023/9/26 17:31 <br>
     * @Version： V2.0.2<br>
     */
    public String buildTableStatisticsDatadQueryField(List<TableFieldsEntity> tableFieldsEntities) {
        List<String> queryFields = new ArrayList<>();
        for (TableFieldsEntity tableFieldsEntity : tableFieldsEntities) {
            String fieldType = tableFieldsEntity.getType().toLowerCase();
            String fileName = tableFieldsEntity.getName();
            String template = "sum(fnv_hash(cast({} as string))) as {}_hash, sum(length(cast({} as string))) as {}_sum";
            if ("string".equals(fieldType) || fieldType.startsWith("char(")) {
                template = "sum(fnv_hash({})) as {}_hash, sum(length({})) as {}_length";
            } else if (Arrays.binarySearch(IMPALA_NUMBER_TYPE, fieldType) >= 0 || fieldType.startsWith("decimal(")) {
                template = "sum(fnv_hash(cast({} as string))) as {}_hash, sum({}) as {}_sum";
            }
            queryFields.add(StrUtil.format(template, fileName, fileName, fileName, fileName));
        }
        return StrUtil.join(",", queryFields);
    }

    /*
     * @Method: queryTableData <br>
     * @Param: [conn, querySql] <br>
     * @Return: java.util.List <br>
     * @Description：指定SQL查询<br>
     * @Author： wz.li<br>
     * @Date： 2023/9/27 11:21 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public List queryTableData(Connection conn, String querySql) {
        Statement statement = null;
        ResultSet resultSet = null;
        try {
            statement = conn.createStatement();
            resultSet = statement.executeQuery(querySql);
            List queryResult = new ArrayList<>();
            while (resultSet.next()) {
                ResultSetMetaData metaData = resultSet.getMetaData();
                Map<String, String> queryDataMap = new HashMap<>();
                for (int i = 1; i <= metaData.getColumnCount(); i++) {
                    queryDataMap.put(metaData.getColumnName(i), resultSet.getString(i));
                }
                queryResult.add(queryDataMap);
            }
            return queryResult;
        } catch (Exception e) {
            throw new RuntimeException(StrUtil.format("指定SQL: {}, 查询异常: {}", querySql, e.getMessage()), e);
        } finally {
            DataSourceUtil.close(statement, resultSet);
        }
    }

    @Override
    public List<String> getDbList(Connection conn) {
        return null;
    }

    @Override
    public List<String> getTableList(Connection conn, String dbName) {
        return null;
    }

    @Override
    public List<String> queryTablePartitionList(Connection conn, String dbName, String tableName) {
        return null;
    }

    @Override
    public void truncateTable(Connection conn, String dbName, String tableName) {

    }

    @Override
    public void dropTable(Connection conn, String dbName, String tableName) {

    }

    @Override
    public String getCreateTableSql(Connection conn, String dbName, String tableName) {
        return null;
    }

    @Override
    public void delTablePartition(Connection conn, String dbName, String tableName, String partitionName, String partitionVal) {

    }

    @Override
    public ResultSet executeQuery(Connection conn, String querySql) {
        return null;
    }
}
